﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using GDCal.vo;
using GDCal.dao;
using System.Collections;
using ESRI.ArcGIS.GISClient;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.Carto;
using System.IO;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using System.Threading;
using System.Globalization;
using MyArcMapLib;

namespace GDCal
{
    public partial class GDCal : GDBaseForm
    {
        private ContextMenuStrip treeContextMenuStrip;
        private ToolStripMenuItem deleteStripMenuItem;
        private ToolStripMenuItem renameStripMenuItem;
        private ToolStripMenuItem refreshStripMenuItem;
        private ToolStripMenuItem connectStripMenuItem;
        private ToolStripMenuItem disconnectStripMenuItem;
        private Dictionary<String, IAGSServerObjectName> loadedMapServiceInformations;

        //Variable for full detail list view when click on arc gis server item, not map service item.
        private ListView fullDetailListView;
        private ColumnHeader nameColumn;
        private ColumnHeader typeColumn;
        private Label landAreaInfoLabel;
        private ListView landAreaInfoListView;
        private ColumnHeader cityColumn;
        private ColumnHeader yearColumn;
        private ColumnHeader landLayerColumn;
        private ColumnHeader landAreaAttrColumn;

        //Variable for detail panel when click on map service item
        private Panel detailPanel;
        private Label serviceLabel, serviceValue, urlLabel, urlValue;

        //Variable for selected street feature layer
        private IFeatureLayer selectedStreetFeatureLayer;
        private IFeatureLayer selectedLandAreaFeatureLayer;
        private Boolean isWorkWithMapServer = false;

        private ArrayList streetTypes;
        private Dictionary<String, ArrayList> landAreaInformations;
        private Dictionary<String, double> landPrices;
        private Dictionary<String, double> areaPrices;

        //Variable for price calculation tab
        private ComboBox onflyCombo;
        private ComboBox defaultOnflyCombo;
        private ComboBox areaOnflyCombo;
        private LandPriceCalculateHelper landPriceCalculateHelper;

        public GDCal()
        {
            if (!LandPriceCalculateHelper.checkIfSystemRegistered())
            {
                MessageBox.Show(GDCalMessages.Notify_SystemNotRegistered, GDCalMessages.Notify_Caption);
                System.Environment.Exit(0);
            }


            //load ini file to read db information
            bool showErrorAndStop = false;
            String message = AbstractDao.connectToServer();
            if (!GDCalConstants.testConnectionToDBOK.Equals(message))
            {
                showErrorAndStop = true;
                MessageBox.Show(message, GDCalMessages.Notify_Caption);
            }

            //If can not connect db, make the whole application is readonly.
            if (showErrorAndStop)
            {
                System.Environment.Exit(0);
            } 
            
            ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Desktop);
            InitializeComponent();
            
            //update to correct client size
            this.splitContainer1.Height = this.ClientRectangle.Height - 75;
            
            showMaximize(true);
            
            //Load all registered arc gis server
            loadAllRegisteredArcGisServers();

            //set auto expand the root one.
            mainTree.Nodes[0].NodeFont = new Font(mainTree.Font, FontStyle.Bold);
            mainTree.Nodes[0].Text = mainTree.Nodes[0].Text;
            mainTree.Nodes[0].ExpandAll();
            this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);

            //init menu context
            initMenuContextForTree();
            loadedMapServiceInformations = new Dictionary<String, IAGSServerObjectName>();
            initFullDetailListView();
            initDetailPanel();
            initLandAreaInfoLabel();
            this.previewMapControl.Size = new System.Drawing.Size(this.mainTab2.Width, this.mainTab2.Height);

            //show/hide control in 3rd tab
            showHideControlsIn3rdTabForStep(-1);
            landPriceCalculateHelper = new LandPriceCalculateHelper();
        }

        private void arcGISServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showAddServerForm();
        }

        private void folderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showAddFolderDialog();
        }

        private void showAddServerForm() 
        {
            AddServerForm addServerForm = new AddServerForm(this);
            addServerForm.ShowDialog();

            ArcGISServerInfoVO ret = addServerForm.getArcGISServerInfo();
            if (!String.IsNullOrEmpty(ret.getName()))
            {
                //Store to database
                ArcGISServerInfoDao.insertArcGISServerInfo(ret);

                //Add to tree
                ret = (ArcGISServerInfoVO)ArcGISServerInfoDao.filter(ret)[0];
                mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes.Add(Convert.ToString(ret.getId()), ret.getName());
                mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Expand();
            }
        }

        private void showAddFolderDialog()
        {
            try
            {
                String startupPath = Application.StartupPath;
                using (FolderBrowserDialog dialog = new FolderBrowserDialog())
                {
                    dialog.Description = GDCalMessages.FolderDialogDescription;
                    dialog.ShowNewFolderButton = false;
                    dialog.RootFolder = Environment.SpecialFolder.MyComputer;
                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        String folder = dialog.SelectedPath;
                        //Store to db
                        ArcGISServerInfoVO serverInfo = new ArcGISServerInfoVO();
                        serverInfo.setName(folder);
                        serverInfo.setType(ArcGISServerInfoVO.ArcGIS_Folder);
                        serverInfo.setUrl(folder);
                        ArcGISServerInfoDao.insertArcGISServerInfo(serverInfo);

                        //Reload the value stored to db and create new node on tree
                        serverInfo = (ArcGISServerInfoVO)ArcGISServerInfoDao.filter(serverInfo)[0];
                        mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Nodes.Add(Convert.ToString(serverInfo.getId()), serverInfo.getName());
                        mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Expand();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(GDCalMessages.Notify_ErrorWhenOpenFolderDialog + "\n" + ex.Message, GDCalMessages.Notify_Caption);
            }
        }

        private void loadAllRegisteredArcGisServers() {
            ArrayList registeredServers = ArcGISServerInfoDao.filter(new ArcGISServerInfoVO());
            foreach (ArcGISServerInfoVO server in registeredServers)
            {
                if (ArcGISServerInfoVO.ArcGIS_Folder.Equals(server.getType()))
                {
                    mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Nodes.Add(Convert.ToString(server.getId()), server.getName());
                }
                else
                {
                    mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes.Add(Convert.ToString(server.getId()), server.getName());
                }
            }
            mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Expand();
            mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Expand();
        }

        private void mainTree_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            TreeNode node = e.Node;
            if (node.Level == 2 && node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
            {
                if (node.Index == 0)
                {
                    showAddServerForm();
                }
                else 
                {
                    if (node.Nodes.Count == 0)
                    {
                        clearMapFromServer();
                        showHideControlsIn3rdTabForStep(-1);
                        loadArcGISServerDetail(node);
                    }
                    else
                    {
                        node.Expand();
                    }
                }
            }
            if (node.Level == 2 && node.Parent.Name.Equals(GDCalConstants.folderParentNodeName))
            {
                if (node.Index == 0)
                {
                    showAddFolderDialog();
                }
                else
                {
                    if (node.Nodes.Count == 0)
                    {
                        clearMapFromServer();
                        showHideControlsIn3rdTabForStep(-1);
                        loadFolderDetail(node);
                    }
                    else
                    {
                        node.Expand();
                    }
                }
            }
        }

        private void loadArcGISServerDetail(TreeNode node)
        {
            node.Nodes.Clear();
            int id = Convert.ToInt32(node.Name);
            ArcGISServerInfoVO selectedServer = ArcGISServerInfoDao.getArcGISServerInfo(id);

            //load all service from arc gis server
            loadAllServiceOfArcGISServer(selectedServer, node);
            if (node.Nodes.Count == 0)
            {
                node.NodeFont = new Font(mainTree.Font, FontStyle.Regular);
                MessageBox.Show(GDCalMessages.Notify_NoServerInfo, GDCalMessages.Notify_Caption);
            }
            else
            {
                node.NodeFont = new Font(mainTree.Font, FontStyle.Bold);
                node.Text = node.Text;
                this.mainTab1.Controls.Clear();
                updateFullDetailListView(buildDataForServerNode(node));
                this.mainTab1.Controls.Add(fullDetailListView);
            }
        }

        private void loadFolderDetail(TreeNode node) 
        {
            node.Nodes.Clear();
            int id = Convert.ToInt32(node.Name);
            ArcGISServerInfoVO selectedServer = ArcGISServerInfoDao.getArcGISServerInfo(id);

            //load all map document from folder
            loadAllMapDocuments(selectedServer, node);
            if (node.Nodes.Count == 0)
            {
                node.NodeFont = new Font(mainTree.Font, FontStyle.Regular);
                MessageBox.Show(GDCalMessages.Notify_NoMxdDocument, GDCalMessages.Notify_Caption);
            }
            else
            {
                node.NodeFont = new Font(mainTree.Font, FontStyle.Bold);
                node.Text = node.Text;
                this.mainTab1.Controls.Clear();
                updateFullDetailListView(buildDataForServerNode(node));
                this.mainTab1.Controls.Add(fullDetailListView);
            }
        }

        private IAGSServerConnection getArcGISServerConnection(ArcGISServerInfoVO selectedServer)
        {
            ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Desktop);

            IAGSServerConnectionFactory agsServerConnectionFactory = new AGSServerConnectionFactory();
            IPropertySet connectionProps = new PropertySet();
            IAGSServerConnection agsServerConnection = null;
            if (selectedServer.getType().Equals(ArcGISServerInfoVO.ArcGIS_Server_Local))
            {
                connectionProps.SetProperty("machine", selectedServer.getHostName());
            }
            else
            {
                connectionProps.SetProperty("URL", selectedServer.getUrl());
                connectionProps.SetProperty("user", selectedServer.getUserName());
                connectionProps.SetProperty("password", selectedServer.getPassword());
            }

            try
            {
                agsServerConnection = agsServerConnectionFactory.Open(connectionProps, 0);
                System.Runtime.InteropServices.Marshal.FinalReleaseComObject(agsServerConnectionFactory);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, GDCalMessages.Notify_Caption);
            }
            return agsServerConnection;
        }

        private IMap getMapFromMapServer(IAGSServerObjectName pSOName)
        {
            IServerContext serverContext = getServerContextFromMapServer(pSOName);
            IMapServer iMapServer = serverContext.ServerObject as IMapServer;
            IMapServerObjects mapServerObject = iMapServer as IMapServerObjects;
            IMap map = mapServerObject.get_Map(iMapServer.DefaultMapName);
            serverContext.ReleaseContext();
            return map;
        }

        private IServerContext getServerContextFromMapServer(IAGSServerObjectName pSOName)
        {
            ArcGISServerInfoVO selectedServer = ArcGISServerInfoDao.getArcGISServerInfo(Convert.ToInt32(mainTree.SelectedNode.Parent.Name));
            IAGSServerConnection agsServerConnection = getArcGISServerConnection(selectedServer);
            IAGSServerConnectionAdmin agsServerConnectionAdmin = (IAGSServerConnectionAdmin)agsServerConnection;
            IServerObjectManager serverObjectManager = agsServerConnectionAdmin.ServerObjectManager;
            IServerContext serverContext = serverObjectManager.CreateServerContext(pSOName.Name, pSOName.Type);
            return serverContext;
        }

        private void loadAllServiceOfArcGISServer(ArcGISServerInfoVO selectedServer, TreeNode node) 
        {
            setWaitingMode(GDCalMessages.Status_ReadServerInfo, this.mainStatus, this.mainStatusLabel);
            IAGSServerConnection agsServerConnection = getArcGISServerConnection(selectedServer);

            if (agsServerConnection != null)
            {
                IAGSEnumServerObjectName enumSOName = agsServerConnection.ServerObjectNames;
                if (enumSOName != null)
                {
                    IAGSServerObjectName pSOName = enumSOName.Next();
                    while (pSOName != null)
                    {
                        node.Nodes.Add(pSOName.Name);
                        loadedMapServiceInformations.Add(node.Index + "_" + pSOName.Name, pSOName);
                        pSOName = enumSOName.Next();
                    }
                }
            }
            node.Expand();
            this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
        }

        private void loadAllMapDocuments(ArcGISServerInfoVO selectedServer, TreeNode node)
        {
            setWaitingMode(GDCalMessages.Status_ScanFolderToGetInfo, this.mainStatus, this.mainStatusLabel);
            readFolderRecursive(selectedServer.getUrl(), node);
            node.Expand();
            this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
        }

        private void readFolderRecursive(String parentPath, TreeNode parentNode) 
        {
            foreach (String folderName in Directory.GetDirectories(parentPath, "*", SearchOption.TopDirectoryOnly))
            {
                DirectoryInfo directoryInfo = new DirectoryInfo(folderName);
                TreeNode folderNode = new TreeNode(directoryInfo.Name);
                readFolderRecursive(folderName, folderNode);

                if (folderNode.Nodes.Count > 0)
                    parentNode.Nodes.Add(folderNode);
            }
            foreach (String fileName in Directory.GetFiles(parentPath, "*.mxd", SearchOption.TopDirectoryOnly))
            {
                FileInfo fileInfo = new FileInfo(fileName);
                TreeNode node = new TreeNode(fileInfo.Name.Replace(".mxd", ""));
                node.Name = fileName;
                parentNode.Nodes.Add(node);
            }
        }

        public void updateMainStatusFromDialog(String message)
        {
            if (String.IsNullOrEmpty(message))
                this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
            else
                this.setWaitingMode(message, this.mainStatus, this.mainStatusLabel);
        }

        public TreeNodeCollection getTreeNodeCollection() 
        {
            return mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes;
        }

        public void initMenuContextForTree()
        {
            deleteStripMenuItem = new ToolStripMenuItem();
            deleteStripMenuItem.Name = "deleteStripMenuItem";
            deleteStripMenuItem.ShortcutKeyDisplayString = "";
            deleteStripMenuItem.Size = new System.Drawing.Size(234, 22);
            deleteStripMenuItem.Text = "Xoá";
            deleteStripMenuItem.Click += new System.EventHandler(this.deleteStripMenuItem_Click);

            renameStripMenuItem = new ToolStripMenuItem();
            renameStripMenuItem.Name = "renameStripMenuItem";
            renameStripMenuItem.ShortcutKeyDisplayString = "";
            renameStripMenuItem.Size = new System.Drawing.Size(234, 22);
            renameStripMenuItem.Text = "Đổi tên";
            renameStripMenuItem.Click += new System.EventHandler(this.renameStripMenuItem_Click);

            refreshStripMenuItem = new ToolStripMenuItem();
            refreshStripMenuItem.Name = "refreshStripMenuItem";
            refreshStripMenuItem.ShortcutKeyDisplayString = "";
            refreshStripMenuItem.Size = new System.Drawing.Size(234, 22);
            refreshStripMenuItem.Text = "Làm mới";
            refreshStripMenuItem.Click += new System.EventHandler(this.refreshStripMenuItem_Click);

            connectStripMenuItem = new ToolStripMenuItem();
            connectStripMenuItem.Name = "connectStripMenuItem";
            connectStripMenuItem.ShortcutKeyDisplayString = "";
            connectStripMenuItem.Size = new System.Drawing.Size(234, 22);
            connectStripMenuItem.Text = "Kết nối";
            connectStripMenuItem.Click += new System.EventHandler(this.refreshStripMenuItem_Click);

            disconnectStripMenuItem = new ToolStripMenuItem();
            disconnectStripMenuItem.Name = "disconnectStripMenuItem";
            disconnectStripMenuItem.ShortcutKeyDisplayString = "";
            disconnectStripMenuItem.Size = new System.Drawing.Size(234, 22);
            disconnectStripMenuItem.Text = "Ngắt kết nối";
            disconnectStripMenuItem.Click += new System.EventHandler(this.disconnectStripMenuItem_Click);

            treeContextMenuStrip = new ContextMenuStrip();
            this.treeContextMenuStrip.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.treeContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
                deleteStripMenuItem,
                renameStripMenuItem,
                refreshStripMenuItem,
                new ToolStripSeparator(),
                connectStripMenuItem,
                disconnectStripMenuItem});
        }

        private void mainTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                TreeNode node = e.Node;
                mainTree.SelectedNode = node;
                if (node.Level == 2 && node.Index > 0)
                {
                    node.ContextMenuStrip = treeContextMenuStrip;
                    if (node.Nodes.Count == 0)
                    {
                        connectStripMenuItem.Enabled = true;
                        disconnectStripMenuItem.Enabled = false;
                    }
                    else
                    {
                        connectStripMenuItem.Enabled = false;
                        disconnectStripMenuItem.Enabled = true;
                    }
                }
            }
            else
            {
                mainTree.LabelEdit = false;
                this.mainTab1.Controls.Clear();
                //Check if level 2 of the tree (Arcgis server root node / Folder root node)
                if (e.Node.Level == 2)
                {
                    // If not the add new node
                    if (e.Node.Index > 0 && e.Node.Nodes.Count > 0)
                    {
                        updateFullDetailListView(buildDataForServerNode(e.Node));
                        this.mainTab1.Controls.Add(this.fullDetailListView);
                        if (this.mainTabControl.SelectedTab == this.mainTab2)
                        {
                            clearMapFromServer();
                            showHideControlsIn3rdTabForStep(-1);
                        }
                        if (this.mainTabControl.SelectedTab == this.mainTab3)
                        {
                            showHideControlsIn3rdTabForStep(-1);
                        }
                    }
                }
                else
                {
                    //Check if child node of arcgis server node or folder node
                    if (e.Node.Level >= 3)
                    {
                        //If map service (under arcgis server node), show service information
                        if (e.Node.Parent.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
                        {
                            IAGSServerObjectName pSOName = loadedMapServiceInformations[e.Node.Parent.Index + "_" + e.Node.Text];
                            updateDetailPanel(pSOName.Name, GDCalConstants.mapServiceType);
                            updateLandAreaInfoLabel(e.Node);
                            this.mainTab1.Controls.Add(this.detailPanel);
                            this.mainTab1.Controls.Add(this.landAreaInfoLabel);
                            this.mainTab1.Controls.Add(this.landAreaInfoListView);
                            //load map
                            if (this.mainTabControl.SelectedTab == this.mainTab2)
                            {
                                loadMapFromServer(pSOName);
                                showHideControlsIn3rdTabForStep(0);
                            }
                        }
                        else
                        {
                            //If folder node, show folder information (include the first child node)
                            if (e.Node.Nodes.Count > 0)
                            {
                                updateFullDetailListView(buildDataForServerNode(e.Node));
                                this.mainTab1.Controls.Add(this.fullDetailListView);
                                if (this.mainTabControl.SelectedTab == this.mainTab2)
                                {
                                    clearMapFromServer();
                                    showHideControlsIn3rdTabForStep(-1);
                                }
                            }
                            else
                            {
                                updateDetailPanel(e.Node.Text, GDCalConstants.mxdType);
                                updateLandAreaInfoLabel(e.Node);
                                this.mainTab1.Controls.Add(this.detailPanel);
                                this.mainTab1.Controls.Add(this.landAreaInfoLabel);
                                this.mainTab1.Controls.Add(this.landAreaInfoListView);

                                //load map
                                if (this.mainTabControl.SelectedTab == this.mainTab2)
                                {
                                    loadMapFromMxdFile(e.Node.Name);
                                    showHideControlsIn3rdTabForStep(0);
                                } 
                            }
                        }
                    }
                }
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Environment.Exit(0);
        }

        private void deleteStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = this.mainTree.SelectedNode;
            if (node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
            {
                if (MessageBox.Show(GDCalMessages.Confirm_DeleteServer + node.Text, GDCalMessages.Confirm_Caption, MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes.RemoveAt(node.Index);
                    ArcGISServerInfoDao.delArcGISServerInfo(Convert.ToInt32(node.Name));
                    this.mainTab1.Controls.Clear();
                }
            }
            else
            {
                if (MessageBox.Show(GDCalMessages.Confirm_DeleteFolder + node.Text, GDCalMessages.Confirm_Caption, MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Nodes.RemoveAt(node.Index);
                    ArcGISServerInfoDao.delArcGISServerInfo(Convert.ToInt32(node.Name));
                    this.mainTab1.Controls.Clear();
                }
            }
        }

        private void refreshStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = this.mainTree.SelectedNode;
            if (node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
            {
                loadArcGISServerDetail(node);
            }
            else
            {
                loadFolderDetail(node);
            }
        }

        private void disconnectStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = this.mainTree.SelectedNode;
            node.Nodes.Clear();
            node.NodeFont = new Font(mainTree.Font, FontStyle.Regular);
            node.Collapse();
            this.mainTab1.Controls.Clear();
        }

        private void renameStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode node = this.mainTree.SelectedNode;
            this.mainTree.LabelEdit = true;
            if (!node.IsEditing)
            {
                node.BeginEdit();
            }
        }

        private void mainTree_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            if (e.Label != null)
            {
                if (e.Label.Length > 0)
                {
                    if (e.Label.IndexOfAny(new char[] { '@', ',', '!', '~', '#', '$', '%', '^', '&', '*', '(', ')' }) == -1)
                    {
                        bool ret = false;
                        if (e.Node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
                        {
                            if (mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes != null)
                            {
                                foreach (TreeNode node in mainTree.Nodes[0].Nodes[GDCalConstants.arcGISServerParentNodeIndex].Nodes)
                                {
                                    if (e.Label.Equals(node.Text, StringComparison.OrdinalIgnoreCase) && node.Index != e.Node.Index)
                                    {
                                        ret = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Nodes != null)
                            {
                                foreach (TreeNode node in mainTree.Nodes[0].Nodes[GDCalConstants.folderParentNodeIndex].Nodes)
                                {
                                    if (e.Label.Equals(node.Text, StringComparison.OrdinalIgnoreCase) && node.Index != e.Node.Index)
                                    {
                                        ret = true;
                                        break;
                                    }
                                }
                            }
                        }

                        //Show message if existed
                        if (ret)
                        {
                            if (e.Node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
                                MessageBox.Show(GDCalMessages.Notify_ServerExisted, GDCalMessages.Notify_Caption);
                            else
                                MessageBox.Show(GDCalMessages.Notify_FolderExisted, GDCalMessages.Notify_Caption);
                            e.CancelEdit = true;
                            e.Node.BeginEdit();
                        }
                        else
                        {
                            e.Node.EndEdit(false);
                            ArcGISServerInfoVO editedServer = ArcGISServerInfoDao.getArcGISServerInfo(Convert.ToInt32(e.Node.Name));
                            editedServer.setName(e.Label);
                            ArcGISServerInfoDao.updateArcGISServerInfo(editedServer);
                        }
                    }
                    else
                    {
                        e.CancelEdit = true;
                        if (e.Node.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
                            MessageBox.Show(GDCalMessages.Notify_InvalidCharForServerName +
                                "'@', ',', '!', '~', '#', '$', '%', '^', '&', '*', '(', ')'", GDCalMessages.Notify_Caption);
                        else
                            MessageBox.Show(GDCalMessages.Notify_InvalidCharForFolderName +
                                "'@', ',', '!', '~', '#', '$', '%', '^', '&', '*', '(', ')'", GDCalMessages.Notify_Caption);
                        e.Node.BeginEdit();
                    }
                }
                else
                {
                    e.CancelEdit = true;
                    MessageBox.Show(GDCalMessages.Notify_BlankServerName, GDCalMessages.Notify_Caption);
                    e.Node.BeginEdit();
                }
            }
        }

        private void initLandAreaInfoLabel()
        {
            this.landAreaInfoLabel = new Label();
            this.landAreaInfoLabel.AutoSize = true;
            this.landAreaInfoLabel.Location = new System.Drawing.Point(2, 70);
            this.landAreaInfoLabel.Name = "landAreaInfoLabel";
            this.landAreaInfoLabel.Size = new System.Drawing.Size(100, 16);
            this.landAreaInfoLabel.TabIndex = 1;
            this.landAreaInfoLabel.Text = "Thông tin giá đất đã tính toán:";

            this.landAreaInfoListView = new ListView();
            this.cityColumn = new ColumnHeader();
            this.yearColumn = new ColumnHeader();
            this.landLayerColumn = new ColumnHeader();
            this.landAreaAttrColumn = new ColumnHeader();

            this.landAreaInfoListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.cityColumn,
            this.yearColumn,
            this.landLayerColumn,
            this.landAreaAttrColumn});

            this.landAreaInfoListView.Location = new System.Drawing.Point(0, 90);
            this.landAreaInfoListView.Name = "landAreaInfoListView";
            this.landAreaInfoListView.Size = new System.Drawing.Size(this.mainTab1.Width, this.mainTab1.Height - 90);
            this.landAreaInfoListView.TabIndex = 1;
            this.landAreaInfoListView.UseCompatibleStateImageBehavior = false;
            this.landAreaInfoListView.View = System.Windows.Forms.View.Details;
            this.landAreaInfoListView.GridLines = true;
            this.landAreaInfoListView.FullRowSelect = true;
            this.cityColumn.Text = "Thành phố";
            this.cityColumn.Width = 150;
            this.yearColumn.Text = "Năm";
            this.yearColumn.Width = 50;
            this.landLayerColumn.Text = "Lớp thửa đất";
            this.landLayerColumn.Width = 150;
            this.landAreaAttrColumn.Text = "Thuộc tính mã thửa đất";
            this.landAreaAttrColumn.Width = 150;
            this.landAreaInfoListView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.landAreaInfoListView_MouseDoubleClick);
        }

        private void initFullDetailListView()
        {
            this.fullDetailListView = new ListView();
            this.nameColumn = new ColumnHeader();
            this.typeColumn = new ColumnHeader();

            this.fullDetailListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.nameColumn,
            this.typeColumn});
            this.fullDetailListView.Location = new System.Drawing.Point(0, 0);
            this.fullDetailListView.Name = "fullDetailListView";
            this.fullDetailListView.Size = new System.Drawing.Size(this.mainTab1.Width, this.mainTab1.Height);
            this.fullDetailListView.TabIndex = 0;
            this.fullDetailListView.UseCompatibleStateImageBehavior = false;
            this.fullDetailListView.View = System.Windows.Forms.View.Details;
            this.fullDetailListView.GridLines = true;
            this.nameColumn.Text = "Tên";
            this.nameColumn.Width = 200;
            this.typeColumn.Text = "Kiểu";
            this.typeColumn.Width = 400;
        }

        private void updateFullDetailListView(ListViewItem[] data)
        {
            this.fullDetailListView.Size = new System.Drawing.Size(this.mainTab1.Width, this.mainTab1.Height);
            this.fullDetailListView.Items.Clear();
            this.fullDetailListView.Items.AddRange(data);
        }

        private void updateLandAreaInfoLabel(TreeNode node)
        {
            String mapKey = node.Parent.Name + "_" + node.Text;
            CityLandPriceVO clpFilterObj = new CityLandPriceVO();
            clpFilterObj.setMapKey(mapKey);
            ArrayList clps = CityLandPriceDao.filter(clpFilterObj);
            if (clps.Count > 0)
            {
                this.landAreaInfoListView.Items.Clear();
                ListViewItem[] ret = new ListViewItem[clps.Count];
                int i = 0;

                this.landAreaInfoListView.Size = new System.Drawing.Size(this.mainTab1.Width, this.mainTab1.Height - 90);
                this.landAreaInfoLabel.Visible = true;
                this.landAreaInfoListView.Visible = true;

                foreach (CityLandPriceVO clp in clps)
                {
                    ListViewItem listViewItem = new ListViewItem(new string[] { clp.getCity(), 
                        Convert.ToString(clp.getYear()), clp.getLandLayer(), clp.getLandAreaAttribute(), "Xem"}, -1);
                    listViewItem.StateImageIndex = clp.getId();
                    ret[i++] = listViewItem;    
                }
                this.landAreaInfoListView.Items.AddRange(ret);
            }
            else
            {
                this.landAreaInfoLabel.Visible = false;
                this.landAreaInfoListView.Visible = false;
            }
        }

        private ListViewItem[] buildDataForServerNode(TreeNode serverNode)
        {
            ListViewItem[] ret = new ListViewItem[serverNode.Nodes.Count];
            int i = 0;
            foreach (TreeNode childNode in serverNode.Nodes)
            {
                if (serverNode.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
                {
                    IAGSServerObjectName pSOName = loadedMapServiceInformations[serverNode.Index + "_" + childNode.Text];
                    ListViewItem listViewItem = new ListViewItem(new string[] { pSOName.Name, GDCalConstants.mapServiceType }, -1);
                    listViewItem.StateImageIndex = 0;
                    ret[i++] = listViewItem;
                }
                else
                {
                    String type = GDCalConstants.mxdType;
                    if (childNode.Nodes.Count > 0)
                        type = GDCalConstants.folderType;
                    ListViewItem listViewItem = new ListViewItem(new string[] { childNode.Text, type }, -1);
                    listViewItem.StateImageIndex = 0;
                    ret[i++] = listViewItem;
                }
            }
            return ret;
        }

        private void initDetailPanel()
        {
            this.detailPanel = new Panel();
            this.serviceLabel = new Label();
            this.serviceValue = new Label();
            this.urlLabel = new Label();
            this.urlValue = new Label();
            this.detailPanel.SuspendLayout();

            this.detailPanel.BackColor = System.Drawing.Color.White;
            this.detailPanel.Controls.Add(this.serviceLabel);
            this.detailPanel.Controls.Add(this.serviceValue);
            this.detailPanel.Controls.Add(this.urlLabel);
            this.detailPanel.Controls.Add(this.urlValue);
            this.detailPanel.Location = new System.Drawing.Point(0, 0);
            this.detailPanel.Name = "detailPanel";
            this.detailPanel.Size = new System.Drawing.Size(this.mainTab1.Width, 60);
            this.detailPanel.TabIndex = 0;

            this.serviceLabel.AutoSize = true;
            this.serviceLabel.Location = new System.Drawing.Point(12, 11);
            this.serviceLabel.Name = "serviceLabel";
            this.serviceLabel.Size = new System.Drawing.Size(37, 16);
            this.serviceLabel.TabIndex = 0;
            this.serviceLabel.Text = "Tên:";

            this.serviceValue.AutoSize = true;
            this.serviceValue.Location = new System.Drawing.Point(90, 11);
            this.serviceValue.Name = "serviceValue";
            this.serviceValue.Size = new System.Drawing.Size(38, 16);
            this.serviceValue.TabIndex = 1;
            this.serviceValue.Text = "";

            this.urlLabel.AutoSize = true;
            this.urlLabel.Location = new System.Drawing.Point(12, 31);
            this.urlLabel.Name = "urlLabel";
            this.urlLabel.Size = new System.Drawing.Size(37, 16);
            this.urlLabel.TabIndex = 2;
            this.urlLabel.Text = "Kiểu:";
            
            this.urlValue.AutoSize = true;
            this.urlValue.Location = new System.Drawing.Point(90, 31);
            this.urlValue.Name = "urlValue";
            this.urlValue.Size = new System.Drawing.Size(62, 16);
            this.urlValue.TabIndex = 3;
            this.urlValue.Text = "";

            this.detailPanel.ResumeLayout(false);
            this.detailPanel.PerformLayout();
        }

        private void updateDetailPanel(String service, String type)
        {
            this.detailPanel.Size = new System.Drawing.Size(this.mainTab1.Width, 60);
            this.serviceValue.Text = service;
            this.urlValue.Text = type;
        }

        private void loadMapFromServer(IAGSServerObjectName pSOName)
        {
            setWaitingMode(GDCalMessages.Status_LoadAndDisplayMap, this.mainStatus, this.mainStatusLabel);
            clearMapFromServer();
            this.previewMapControl.Size = new System.Drawing.Size(this.mainTab2.Width, this.mainTab2.Height);
            IMapServerLayer layer = null;
            if(this.loadMapWay == 1)
            {
                IName name = pSOName as IName;
                IMapServer mapServer = name.Open() as IMapServer;

                //Create MapServerLayer using AGS data source
                layer = new MapServerLayer() as IMapServerLayer;
                layer.ServerConnect(pSOName, mapServer.DefaultMapName);
            }
            else
            {
                ILayerFactory layerFactory = new MapServerLayerFactory();
                layer = layerFactory.Create(pSOName).Next() as IMapServerLayer;
            }
            previewMapControl.AddLayer(layer as ILayer);
            previewMapControl.Refresh();
            clearWaitingMode(this.mainStatus, this.mainStatusLabel);
        }

        private void loadMapFromMxdFile(String mxdName)
        {
            setWaitingMode(GDCalMessages.Status_ReadMxdAndDisplayMap, this.mainStatus, this.mainStatusLabel);
            this.previewMapControl.Size = new System.Drawing.Size(this.mainTab2.Width, this.mainTab2.Height);

            //load mxd file
            if(previewMapControl.CheckMxFile(mxdName)) {
                clearMapFromServer();
                previewMapControl.LoadMxFile(mxdName, Type.Missing, Type.Missing);
                previewMapControl.Refresh();
            }
            
            clearWaitingMode(this.mainStatus, this.mainStatusLabel);
        }

        private void mainTab2_Enter(object sender, EventArgs e)
        {
            TreeNode node = this.mainTree.SelectedNode;
            if (node.Level == 3 && node.Parent.Parent.Name.Equals(GDCalConstants.arcGISServerParentNodeName))
            {
                IAGSServerObjectName pSOName = loadedMapServiceInformations[node.Parent.Index + "_" + node.Text];
                loadMapFromServer(pSOName);
                showHideControlsIn3rdTabForStep(0);
            }
            else
            {
                if (node.Level >= 3 && node.Nodes.Count == 0)
                {
                    loadMapFromMxdFile(node.Name);
                    showHideControlsIn3rdTabForStep(0);
                }
                else
                {
                    clearMapFromServer();
                    showHideControlsIn3rdTabForStep(-1);
                }
            }
        }

        private void clearMapFromServer()
        {
            while (previewMapControl.LayerCount > 0)
            {
                previewMapControl.DeleteLayer(0);
            }
            previewMapControl.Refresh();
        }

        private void showHideControlsIn3rdTabForStep(int step)
        {
            if (step < 0)
            {
                if (this.mainTabControl.SelectedTab == this.mainTab3)
                {
                    this.mainTabControl.SelectTab(this.mainTab2);
                }
                this.mainTabControl.TabPages.Remove(this.mainTab3);
                this.streetTypeCombo.Items.Clear();
                this.streetTypeAttributeCombo.Items.Clear();
                this.streetNameAttributeCombo.Items.Clear();
                this.landAreaCombo.Items.Clear();
                this.landAreaAttributeCombo.Items.Clear();
                this.landCodeAttributeCombo.Items.Clear();
            }
            else
            {
                if (this.mainTabControl.TabPages.IndexOf(this.mainTab3) < 0)
                {
                    this.mainTabControl.TabPages.Add(this.mainTab3);
                }

                this.landAreaLayerLabel.Visible = step >= 0;
                this.landAreaCombo.Visible = step >= 0;

                this.landAreaAttribute.Visible = step >= 1;
                this.landAreaAttributeCombo.Visible = step >= 1;
                this.landCodeAttribute.Visible = step >= 1;
                this.landCodeAttributeCombo.Visible = step >= 1;

                this.listLandAreaLabel.Visible = step >= 2;
                this.landAreaListView.Visible = step >= 2;
                this.streetTypeRadio.Visible = step >= 2;
                this.areaTypeRadio.Visible = step >= 2;
                if (!this.streetTypeRadio.Checked && !this.areaTypeRadio.Checked)
                    this.streetTypeRadio.Checked = true;
                this.streetTypeLayerLabel.Visible = step >= 2;
                this.streetTypeCombo.Visible = step >= 2;

                this.streetTypeAttributes.Visible = step >= 3;
                this.streetTypeAttributeCombo.Visible = step >= 3;
                this.streetNameAttribute.Visible = step >= 3;
                this.streetNameAttributeCombo.Visible = step >= 3;

                this.streetTypeMappingLabel.Visible = step >= 4;
                this.streetTypeMappingListView.Visible = step >= 4;

                this.yearLabel.Visible = step >= 5;
                this.yearUpDown.Visible = step >= 5;
                this.cityLabel.Visible = step >= 5;
                this.cityCombo.Visible = step >= 5;
                this.calButton.Visible = step >= 5;
                this.saveButton.Visible = step >= 5;
                this.saveButton.Enabled = false;
                this.bufferLabel.Visible = step >= 5;
                this.bufferUpDown.Visible = step >= 5;
                this.streetRadio.Visible = step >= 5;
                this.areaRadio.Visible = step >= 5;
                this.groupCalType.Visible = step >= 5;

                if (step == 0)
                {
                    this.streetTypeCombo.Items.Clear();
                    this.landAreaCombo.Items.Clear();
                    if (previewMapControl.LayerCount > 0)
                    {
                        int i = 0;
                        while (i < previewMapControl.LayerCount)
                        {
                            ILayer layer = previewMapControl.get_Layer(i);
                            if (layer.GetType() == typeof(MapServerLayerClass))
                            {
                                ICompositeLayer2 compositeLayers = (ICompositeLayer2)layer;
                                for (int j = 0; j < compositeLayers.Count; j++)
                                {
                                    this.streetTypeCombo.Items.Add(compositeLayers.get_Layer(j).Name);
                                    this.landAreaCombo.Items.Add(compositeLayers.get_Layer(j).Name);
                                }
                            }
                            else
                            {
                                this.streetTypeCombo.Items.Add(layer.Name);
                                this.landAreaCombo.Items.Add(layer.Name);
                            }
                            i++;
                        }
                    }
                    selectedStreetFeatureLayer = null;
                    selectedLandAreaFeatureLayer = null;
                    onflyCombo = new ComboBox();
                    defaultOnflyCombo = new ComboBox();
                    areaOnflyCombo = new ComboBox();
                    initAllItemForStreetTypeMapping();
                    onflyCombo.Leave += new System.EventHandler(onflyCombo_Leave);
                    defaultOnflyCombo.Leave += new System.EventHandler(defaultOnflyCombo_Leave);
                    areaOnflyCombo.Leave += new System.EventHandler(areaOnflyCombo_Leave);
                    cancelProcessButton.Location = calButton.Location;
                    cancelProcessButton.Visible = false;
                }
                if (step >= 5)
                {
                    Int32 currentYear = DateTime.Now.Year;
                    yearUpDown.Minimum = currentYear - 10;
                    yearUpDown.Maximum = currentYear + 10;
                    yearUpDown.Value = currentYear;
                    cityCombo.Items.Clear();
                    foreach (String city in this.getCities(Convert.ToInt32(yearUpDown.Value)))
                        this.cityCombo.Items.Add(city);
                    bufferUpDown.Minimum = 0;
                    bufferUpDown.Maximum = 20;
                    bufferUpDown.Value = 1;
                    if (this.areaTypeRadio.Checked)
                    {
                        this.streetRadio.Enabled = false;
                        this.areaRadio.Enabled = false;
                        this.areaRadio.Checked = true;
                        this.streetNameAttribute.Visible = false;
                        this.streetNameAttributeCombo.Visible = false;
                        this.streetNameAttributeCombo.SelectedIndex = -1;
                        this.streetNameAttributeCombo.SelectedText = "";
                    }
                    else
                    {
                        this.streetRadio.Enabled = true;
                        this.areaRadio.Enabled = true;
                        this.streetRadio.Checked = true;
                        this.streetNameAttribute.Visible = true;
                        this.streetNameAttributeCombo.Visible = true;
                    }
                }
            }
        }

        private void streetTypeCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            showHideControlsIn3rdTabForStep(3);
            if (this.streetTypeCombo.SelectedIndex < 0) return;
            String selectedLayerName = (String)this.streetTypeCombo.Items[this.streetTypeCombo.SelectedIndex];
            if (previewMapControl.LayerCount > 0)
            {
                int i = 0;
                while (i < previewMapControl.LayerCount)
                {
                    ILayer layer = previewMapControl.get_Layer(i);
                    //map service from map server
                    if (layer.GetType() == typeof(MapServerLayerClass) || isWorkWithMapServer)
                    {
                        ICompositeLayer compositeLayers = (ICompositeLayer)layer;
                        for (int j = 0; j < compositeLayers.Count; j++)
                        {
                            if (compositeLayers.get_Layer(j).Name.Equals(selectedLayerName))
                            {
                                IAGSServerObjectName pSOName = loadedMapServiceInformations[mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text];
                                IMap map = getMapFromMapServer(pSOName);
                                this.streetTypeAttributeCombo.Items.Clear();
                                this.streetTypeAttributeCombo.SelectedText = "";
                                this.streetNameAttributeCombo.Items.Clear();
                                this.streetNameAttributeCombo.SelectedText = "";
                                IFeatureLayer featureLayer = map.get_Layer(j) as IFeatureLayer;
                                selectedStreetFeatureLayer = featureLayer;
                                break;
                            }
                        }
                    }
                    else
                    {
                        //load from mxd file
                        if (layer.Name.Equals(selectedLayerName))
                        {
                            this.streetTypeAttributeCombo.Items.Clear();
                            this.streetTypeAttributeCombo.SelectedText = "";
                            this.streetNameAttributeCombo.Items.Clear();
                            this.streetNameAttributeCombo.SelectedText = "";
                            IFeatureLayer featureLayer = (IFeatureLayer)layer;
                            selectedStreetFeatureLayer = featureLayer;
                            break;
                        }
                    }
                    i++;
                }
                if (selectedStreetFeatureLayer != null)
                {
                    IFeatureClass featureClass = selectedStreetFeatureLayer.FeatureClass;
                    ITable table = (ITable)featureClass;
                    IFields fields = table.Fields;
                    for (int k = 0; k < fields.FieldCount; k++)
                    {
                        IField field = fields.get_Field(k);
                        this.streetTypeAttributeCombo.Items.Add(field.Name);
                        this.streetNameAttributeCombo.Items.Add(field.Name);
                    }
                }
            }
        }

        private void streetTypeAttributeCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            String fieldName = (String)this.streetTypeAttributeCombo.Items[this.streetTypeAttributeCombo.SelectedIndex];
            if (selectedStreetFeatureLayer != null)
            {
                //check and load attribute for selected layer with map service from map server
                if(loadedMapServiceInformations.ContainsKey(mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text))
                {
                    IAGSServerObjectName pSOName = loadedMapServiceInformations[mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text];
                    IServerContext serverContext = getServerContextFromMapServer(pSOName);
                    ISpatialFilter pSpatialFilter = serverContext.CreateObject("esriGeodatabase.SpatialFilter") as ISpatialFilter;
                    pSpatialFilter.SubFields = fieldName;

                    IQueryFilterDefinition filterDef = (IQueryFilterDefinition)pSpatialFilter;
                    filterDef.PostfixClause = "GROUP BY " + fieldName + " ORDER BY " + fieldName;

                    ITable queryTable = selectedStreetFeatureLayer.FeatureClass.GetFeature(this.streetTypeAttributeCombo.SelectedIndex + 1).Table;
                    ICursor cursor = queryTable.Search(pSpatialFilter, true);

                    IRow row = null;
                    streetTypes = new ArrayList();
                    while ((row = cursor.NextRow()) != null)
                    {
                        String value = Convert.ToString(row.get_Value(this.streetTypeAttributeCombo.SelectedIndex));
                        if (!streetTypes.Contains(value) && !String.IsNullOrEmpty(value))
                            streetTypes.Add(value);
                    }
                    serverContext.ReleaseContext();
                }
                else
                {
                    //Check and load attribute for selected layer with map from mxd file
                    IQueryFilter filter = new QueryFilterClass();
                    filter.SubFields = fieldName;

                    IQueryFilterDefinition filterDef = (IQueryFilterDefinition)filter;
                    filterDef.PostfixClause = "GROUP BY " + fieldName + " ORDER BY " + fieldName;

                    ITable queryTable = selectedStreetFeatureLayer.FeatureClass.GetFeature(this.streetTypeAttributeCombo.SelectedIndex + 1).Table;
                    ICursor cursor = queryTable.Search(filter, true);
                    IRow row = null;
                    streetTypes = new ArrayList();
                    while ((row = cursor.NextRow()) != null)
                    {
                        String value = Convert.ToString(row.get_Value(this.streetTypeAttributeCombo.SelectedIndex));
                        if (!streetTypes.Contains(value) && !String.IsNullOrEmpty(value))
                            streetTypes.Add(value);
                    }
                }
                showHideControlsIn3rdTabForStep(4);
                streetTypeMappingListView.Items.Clear();
                initAllItemForStreetTypeMapping();

                String[] items = new String[2] { GDCalConstants.defaultType, "" };
                streetTypeMappingListView.Items.Add(new ListViewItem(items));
                if (streetTypes != null && streetTypes.Count > 0)
                {
                    foreach(String type in streetTypes) 
                    {
                        items = new String[2] {type, ""};
                        streetTypeMappingListView.Items.Add(new ListViewItem(items));
                    }
                    showHideControlsIn3rdTabForStep(5);
                }
            }
        }

        private void streetTypeMappingListView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            streetTypeMappingListView.Controls.Remove(onflyCombo);
            streetTypeMappingListView.Controls.Remove(defaultOnflyCombo);
            streetTypeMappingListView.Controls.Remove(areaOnflyCombo);
            ListViewItem selectedItem = streetTypeMappingListView.GetItemAt(e.X, e.Y);
            if (selectedItem != null)
            {
                Rectangle rectangleItem = selectedItem.Bounds;
                if (rectangleItem.Left + streetTypeMappingListView.Columns[1].Width < 0 || e.X < streetTypeMappingListView.Columns[0].Width)
                {
                    return;
                }
                else if (rectangleItem.Left < 0)
                {
                    if ((rectangleItem.Left + streetTypeMappingListView.Columns[1].Width) > streetTypeMappingListView.Width)
                    {
                        rectangleItem.Width = streetTypeMappingListView.Width;
                        rectangleItem.X = 0;
                    }
                    else
                    {
                        rectangleItem.Width = streetTypeMappingListView.Columns[1].Width + rectangleItem.Left;
                        rectangleItem.X = 2;
                    }
                }
                else if (streetTypeMappingListView.Columns[1].Width > streetTypeMappingListView.Width)
                {
                    rectangleItem.Width = streetTypeMappingListView.Width;
                }
                else
                {
                    rectangleItem.Width = streetTypeMappingListView.Columns[1].Width;
                    rectangleItem.X = 2;
                }

                rectangleItem.X += streetTypeMappingListView.Columns[0].Width;

                if (areaTypeRadio.Checked)
                {
                    areaOnflyCombo.Bounds = rectangleItem;
                    streetTypeMappingListView.Controls.Add(areaOnflyCombo);
                    if (!String.IsNullOrEmpty(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text))
                    {
                        areaOnflyCombo.Items.Add(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text);
                        areaOnflyCombo.SelectedText = streetTypeMappingListView.SelectedItems[0].SubItems[1].Text;
                    }
                    areaOnflyCombo.Focus();
                }
                else
                {
                    if (GDCalConstants.defaultType.Equals(selectedItem.SubItems[0].Text))
                    {
                        defaultOnflyCombo.Bounds = rectangleItem;
                        streetTypeMappingListView.Controls.Add(defaultOnflyCombo);
                        if (!String.IsNullOrEmpty(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text))
                        {
                            defaultOnflyCombo.Items.Add(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text);
                            defaultOnflyCombo.SelectedText = streetTypeMappingListView.SelectedItems[0].SubItems[1].Text;
                        }
                        defaultOnflyCombo.Focus();
                    }
                    else
                    {
                        onflyCombo.Bounds = rectangleItem;
                        streetTypeMappingListView.Controls.Add(onflyCombo);
                        if (!String.IsNullOrEmpty(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text))
                        {
                            onflyCombo.Items.Add(streetTypeMappingListView.SelectedItems[0].SubItems[1].Text);
                            onflyCombo.SelectedText = streetTypeMappingListView.SelectedItems[0].SubItems[1].Text;
                        }
                        onflyCombo.Focus();
                    }
                }
            }
        }

        private void initAllItemForStreetTypeMapping()
        {
            onflyCombo.Items.Clear();
            onflyCombo.Items.Add("");
            StreetTypeVO filterVO = new StreetTypeVO();
            filterVO.setIsDefault(0);
            ArrayList allStreetTypes = StreetTypeDao.filter(filterVO);
            foreach (StreetTypeVO vo in allStreetTypes)
            {
                onflyCombo.Items.Add(vo.getType());
            }

            defaultOnflyCombo.Items.Clear();
            defaultOnflyCombo.Items.Add("");
            filterVO = new StreetTypeVO();
            filterVO.setIsDefault(1);
            ArrayList allDefaultStreetTypes = StreetTypeDao.filter(filterVO);
            foreach (StreetTypeVO vo in allDefaultStreetTypes)
            {
                defaultOnflyCombo.Items.Add(vo.getType());
            }

            areaOnflyCombo.Items.Clear();
            areaOnflyCombo.Items.Add("");
            AreaTypeVO areaFilterVO = new AreaTypeVO();
            ArrayList allDefaultAreaTypes = AreaTypeDao.filter(areaFilterVO);
            foreach (AreaTypeVO vo in allDefaultAreaTypes)
            {
                areaOnflyCombo.Items.Add(vo.getType());
            }
        }

        private Boolean hasStreetTypeMapping()
        {
            Boolean ret = true;
            ArrayList allStreetTypes = StreetTypeDao.filter(new StreetTypeVO());
            ArrayList allAreaTypes = AreaTypeDao.filter(new AreaTypeVO());
            if (allStreetTypes.Count + 2 == onflyCombo.Items.Count + defaultOnflyCombo.Items.Count && allAreaTypes.Count + 1 == areaOnflyCombo.Items.Count)
                ret = false;
            return ret;
        }

        private void onflyCombo_Leave(object sender, EventArgs e)
        {
            String selectedText = "";
            if(onflyCombo.SelectedIndex >= 0)
                selectedText = (String)onflyCombo.Items[onflyCombo.SelectedIndex];
            streetTypeMappingListView.SelectedItems[0].SubItems[1].Text = selectedText;
            streetTypeMappingListView.Controls.Remove(onflyCombo);
            if (!String.IsNullOrEmpty(selectedText))
                onflyCombo.Items.Remove(selectedText);
            onflyCombo.SelectedIndex = 0;
        }

        private void defaultOnflyCombo_Leave(object sender, EventArgs e)
        {
            String selectedText = "";
            if (defaultOnflyCombo.SelectedIndex >= 0)
                selectedText = (String)defaultOnflyCombo.Items[defaultOnflyCombo.SelectedIndex];
            streetTypeMappingListView.SelectedItems[0].SubItems[1].Text = selectedText;
            streetTypeMappingListView.Controls.Remove(defaultOnflyCombo);
            if (!String.IsNullOrEmpty(selectedText))
                defaultOnflyCombo.Items.Remove(selectedText);
            defaultOnflyCombo.SelectedIndex = 0;
        }

        private void areaOnflyCombo_Leave(object sender, EventArgs e)
        {
            String selectedText = "";
            if (areaOnflyCombo.SelectedIndex >= 0)
                selectedText = (String)areaOnflyCombo.Items[areaOnflyCombo.SelectedIndex];
            streetTypeMappingListView.SelectedItems[0].SubItems[1].Text = selectedText;
            streetTypeMappingListView.Controls.Remove(areaOnflyCombo);
            if (!String.IsNullOrEmpty(selectedText))
                areaOnflyCombo.Items.Remove(selectedText);
            areaOnflyCombo.SelectedIndex = 0;
        }

        private void landAreaCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            showHideControlsIn3rdTabForStep(1);
            if (this.landAreaCombo.SelectedIndex < 0) return;
            String selectedLayerName = (String)this.landAreaCombo.Items[this.landAreaCombo.SelectedIndex];
            if (previewMapControl.LayerCount > 0)
            {
                int i = 0;
                while (i < previewMapControl.LayerCount)
                {
                    ILayer layer = previewMapControl.get_Layer(i);
                    //map service from map server
                    if (layer.GetType() == typeof(MapServerLayerClass) || isWorkWithMapServer)
                    {
                        ICompositeLayer compositeLayers = (ICompositeLayer)layer;
                        for (int j = 0; j < compositeLayers.Count; j++)
                        {
                            if (compositeLayers.get_Layer(j).Name.Equals(selectedLayerName))
                            {
                                IAGSServerObjectName pSOName = loadedMapServiceInformations[mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text];
                                IMap map = getMapFromMapServer(pSOName);
                                this.landAreaAttributeCombo.Items.Clear();
                                this.landCodeAttributeCombo.Items.Clear();
                                IFeatureLayer featureLayer = map.get_Layer(j) as IFeatureLayer;
                                selectedLandAreaFeatureLayer = featureLayer;
                                isWorkWithMapServer = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        //load from mxd file
                        if (layer.Name.Equals(selectedLayerName))
                        {
                            this.landAreaAttributeCombo.Items.Clear();
                            this.landCodeAttributeCombo.Items.Clear();
                            IFeatureLayer featureLayer = (IFeatureLayer)layer;
                            selectedLandAreaFeatureLayer = featureLayer;
                            isWorkWithMapServer = false;
                            break;
                        }
                    }
                    i++;
                }
                if (selectedLandAreaFeatureLayer != null)
                {
                    IFeatureClass featureClass = selectedLandAreaFeatureLayer.FeatureClass;
                    ITable table = (ITable)featureClass;
                    IFields fields = table.Fields;
                    for (int k = 0; k < fields.FieldCount; k++)
                    {
                        IField field = fields.get_Field(k);
                        this.landAreaAttributeCombo.Items.Add(field.Name);
                        this.landCodeAttributeCombo.Items.Add(field.Name);
                    }
                }
            }
        }

        private void landAreaAttributeCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (selectedLandAreaFeatureLayer != null)
            {
                //check and load attribute for selected layer with map service from map server
                if (loadedMapServiceInformations.ContainsKey(mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text))
                {
                    IFeatureSelection featSel = selectedLandAreaFeatureLayer as IFeatureSelection;
                    IQueryFilter filter = new QueryFilterClass();
                    featSel.SelectFeatures(filter, esriSelectionResultEnum.esriSelectionResultNew, false);
                    landAreaListView.Items.Clear();
                    int total = featSel.SelectionSet.Count;
                    this.toolStripProgressBar.Minimum = 0;
                    this.toolStripProgressBar.Value = 0;
                    this.toolStripProgressBar.Maximum = total;
                    this.toolStripProgressBar.Visible = true;
                    this.setWaitingMode(GDCalMessages.Status_LandArea_Scanning, this.mainStatus, this.mainStatusLabel);
                    landAreaInformations = new Dictionary<String, ArrayList>();
                    WorkerParamForMxdServer args = new WorkerParamForMxdServer();
                    args.setColumnName(this.landAreaAttributeCombo.SelectedItem.ToString());
                    args.setLandCodeColumnName(this.landCodeAttributeCombo.SelectedItem.ToString());
                    loadAreaDataBGWorker.RunWorkerAsync(args);
                }
                else
                {
                    //Check and load attribute for selected layer with map from mxd file
                    String fieldName = (String)this.landAreaAttributeCombo.Items[this.landAreaAttributeCombo.SelectedIndex];
                    String landCodeFieldName = (String)this.landCodeAttributeCombo.Items[this.landCodeAttributeCombo.SelectedIndex];
                    IQueryFilter filter = new QueryFilterClass();
                    filter.SubFields = fieldName + ", Shape, Shape.area";
                    IFeatureSelection featSel = selectedLandAreaFeatureLayer as IFeatureSelection;
                    featSel.SelectFeatures(filter, esriSelectionResultEnum.esriSelectionResultNew, false);
                    landAreaListView.Items.Clear();
                    int total = featSel.SelectionSet.Count;
                    this.toolStripProgressBar.Minimum = 0;
                    this.toolStripProgressBar.Value = 0;
                    this.toolStripProgressBar.Maximum = total;
                    this.toolStripProgressBar.Visible = true;
                    this.setWaitingMode(GDCalMessages.Status_LandArea_Scanning, this.mainStatus, this.mainStatusLabel);
                    landAreaInformations = new Dictionary<String, ArrayList>();
                    WorkerParamForMxdLocal args = new WorkerParamForMxdLocal();
                    args.setColumnIndex(this.landAreaAttributeCombo.SelectedIndex);
                    args.setLandCodeColumnIndex(this.landCodeAttributeCombo.SelectedIndex);
                    args.setFieldName(fieldName);
                    args.setLandCodeFieldName(landCodeFieldName);
                    if (this.landAreaAttributeCombo.Items.Contains("Shape.area"))
                        args.setShapeAreaColIndex(this.landAreaAttributeCombo.Items.IndexOf("Shape.area"));
                    else
                        args.setShapeAreaColIndex(-1);
                    if (this.landAreaAttributeCombo.Items.Contains("Shape"))
                        args.setShapeColIndex(this.landAreaAttributeCombo.Items.IndexOf("Shape"));
                    else
                        args.setShapeColIndex(-1);
                    loadAreaDataBGWorker.RunWorkerAsync(args);
                    this.yearUpDown.Focus();
                }
                selectedStreetFeatureLayer = null;
                showHideControlsIn3rdTabForStep(2);
            }
        }

        private Dictionary<String, String> getStreetTypeMapping() 
        {
            Dictionary<String, String> ret = new Dictionary<String, String>();
            String streetType = "";
            for (int i = 0; i < streetTypeMappingListView.Items.Count; i++)
            { 
                streetType = streetTypeMappingListView.Items[i].SubItems[1].Text;
                if (streetType != null && !String.IsNullOrEmpty(streetType))
                {
                    ret.Add(streetTypeMappingListView.Items[i].SubItems[0].Text, streetType);
                }
            }
            return ret;
        }

        private void calButton_Click(object sender, EventArgs e)
        {
            if (!hasStreetTypeMapping())
            {
                if (areaTypeRadio.Checked)
                    MessageBox.Show(GDCalMessages.Notify_AreaTypeMappingNotSelect, GDCalMessages.Notify_Caption);
                else
                    MessageBox.Show(GDCalMessages.Notify_StreetTypeMappingNotSelect, GDCalMessages.Notify_Caption);
            }
            else if (cityCombo.SelectedIndex < 0)
            {
                MessageBox.Show(GDCalMessages.Notify_CityNotSelect, GDCalMessages.Notify_Caption);
            }
            else
            {
                cancelProcessButton.Visible = true;
                calButton.Visible = false;
                setWaitingMode(GDCalMessages.Status_LandPriceCalculating, this.mainStatus, this.mainStatusLabel);
                if (selectedStreetFeatureLayer != null)
                {
                    //check and load attribute for selected layer with map service from map server
                    if (loadedMapServiceInformations.ContainsKey(mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text))
                    {
                        IFeatureSelection featSel = selectedStreetFeatureLayer as IFeatureSelection;
                        IQueryFilter filter = new QueryFilterClass();
                        featSel.SelectFeatures(filter, esriSelectionResultEnum.esriSelectionResultNew, false);
                        int total = featSel.SelectionSet.Count;
                        this.toolStripProgressBar.Minimum = 0;
                        this.toolStripProgressBar.Value = 0;
                        if (this.streetRadio.Checked)
                            this.toolStripProgressBar.Maximum = total;
                        else
                            this.toolStripProgressBar.Maximum = landAreaInformations.Count;
                        this.toolStripProgressBar.Visible = true;
                        WorkerParamForCalMxdServer args = new WorkerParamForCalMxdServer();
                        args.setStreetColumnIndex(this.streetTypeAttributeCombo.SelectedIndex);
                        args.setLandColumnIndex(this.landAreaAttributeCombo.SelectedIndex);
                        args.setStreetColumnName(this.streetTypeAttributeCombo.SelectedItem.ToString());
                        args.setLandColumnName(this.landAreaAttributeCombo.SelectedItem.ToString());
                        args.setStreetNameColumnIndex(this.streetNameAttributeCombo.SelectedIndex);
                        args.setStreetTypeMappings(getStreetTypeMapping());
                        args.setBufferValue(Convert.ToInt32(this.bufferUpDown.Value));
                        args.setLoopByStreet(this.streetRadio.Checked);
                        args.setStreetLayerName(streetTypeCombo.SelectedItem.ToString());
                        IAGSServerObjectName pSOName = loadedMapServiceInformations[mainTree.SelectedNode.Parent.Index + "_" + mainTree.SelectedNode.Text];
                        IServerContext serverContext = getServerContextFromMapServer(pSOName);
                        args.setIServerContext(serverContext);
                        loadAreaDataBGWorker.RunWorkerAsync(args);
                    }
                    else
                    {
                        //Check and load attribute for selected layer with map from mxd file
                        String fieldName = (String)this.streetTypeAttributeCombo.Items[this.streetTypeAttributeCombo.SelectedIndex];
                        IFeatureSelection featSel = selectedStreetFeatureLayer as IFeatureSelection;
                        IQueryFilter filter = new QueryFilterClass();
                        featSel.SelectFeatures(filter, esriSelectionResultEnum.esriSelectionResultNew, false);
                        int total = featSel.SelectionSet.Count;
                        this.toolStripProgressBar.Minimum = 0;
                        this.toolStripProgressBar.Value = 0;
                        if (this.streetRadio.Checked)
                            this.toolStripProgressBar.Maximum = total;
                        else
                            this.toolStripProgressBar.Maximum = landAreaInformations.Count;
                        this.toolStripProgressBar.Visible = true;
                        WorkerParamForCalMxdLocal args = new WorkerParamForCalMxdLocal();
                        args.setStreetColumnIndex(this.streetTypeAttributeCombo.SelectedIndex);
                        args.setLandColumnIndex(this.landAreaAttributeCombo.SelectedIndex);
                        args.setStreetColumnName(fieldName);
                        args.setLandColumnName(this.landAreaAttributeCombo.SelectedItem.ToString());
                        args.setStreetNameColumnIndex(this.streetNameAttributeCombo.SelectedIndex);
                        args.setStreetTypeMappings(getStreetTypeMapping());
                        args.setBufferValue(Convert.ToInt32(this.bufferUpDown.Value));
                        args.setLoopByStreet(this.streetRadio.Checked);
                        args.setStreetLayerName(streetTypeCombo.SelectedItem.ToString());
                        if (this.landAreaAttributeCombo.Items.Contains("Shape.area"))
                            args.setShapeAreaColIndex(this.landAreaAttributeCombo.Items.IndexOf("Shape.area"));
                        else
                            args.setShapeAreaColIndex(-1);
                        if (this.landAreaAttributeCombo.Items.Contains("Shape"))
                            args.setShapeColIndex(this.landAreaAttributeCombo.Items.IndexOf("Shape"));
                        else
                            args.setShapeColIndex(-1);
                        loadAreaDataBGWorker.RunWorkerAsync(args);
                    }
                }
            }
        }

        private void loadAreaDataBGWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (loadAreaDataBGWorker.CancellationPending)
            {
                e.Cancel = true;
                loadAreaDataBGWorker.ReportProgress(this.toolStripProgressBar.Maximum);
                return;
            }
            else
            {
                if (e.Argument.GetType() == typeof(WorkerParamForMxdServer))
                {
                    WorkerParamForMxdServer args = ((WorkerParamForMxdServer)e.Argument);
                    landAreaInformations = landPriceCalculateHelper.scanLandAreaForMxdServer(args,
                        selectedLandAreaFeatureLayer, loadAreaDataBGWorker);
                }
                else if (e.Argument.GetType() == typeof(WorkerParamForMxdLocal))
                {
                    WorkerParamForMxdLocal args = ((WorkerParamForMxdLocal)e.Argument);
                    landAreaInformations = landPriceCalculateHelper.scanLandAreaForMxdLocal(args,
                        selectedLandAreaFeatureLayer, loadAreaDataBGWorker);
                }
                else if (e.Argument.GetType() == typeof(WorkerParamForCalMxdServer))
                {
                    WorkerParamForCalMxdServer args = ((WorkerParamForCalMxdServer)e.Argument);
                    landPriceCalculateHelper.calculateLandAreaForMxdServer(args, areaTypeRadio.Checked, selectedStreetFeatureLayer, selectedLandAreaFeatureLayer, GDCalConstants.defaultType, landAreaInformations, streetTypeCombo.SelectedItem.ToString(), loadAreaDataBGWorker);
                }
                else if (e.Argument.GetType() == typeof(WorkerParamForCalMxdLocal))
                {
                    WorkerParamForCalMxdLocal args = ((WorkerParamForCalMxdLocal)e.Argument);
                    landPriceCalculateHelper.calculateLandAreaForMxdLocal(args, areaTypeRadio.Checked, selectedStreetFeatureLayer, selectedLandAreaFeatureLayer, GDCalConstants.defaultType, landAreaInformations, loadAreaDataBGWorker);
                }
            }
        }

        private void loadAreaDataBGWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripProgressBar.PerformStep(); 
        }

        private void loadAreaDataBGWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.toolStripProgressBar.Visible = false;
            if (cancelProcessButton.Visible)
            {
                cancelProcessButton.Visible = false;
                calButton.Visible = true;
            }
            this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
            int count = 0;
            if (landAreaInformations != null && landAreaInformations.Count > 0)
            {
                landAreaListView.Items.Clear();
                this.setWaitingMode(GDCalMessages.Status_DataRendering, this.mainStatus, this.mainStatusLabel);
                int i = 1;
                loadPriceForCityAtYear(Convert.ToString(cityCombo.SelectedItem), Convert.ToInt16(yearUpDown.Value));
                foreach (String type in landAreaInformations.Keys)
                {
                    ArrayList lais = landAreaInformations[type];
                    foreach (LandAreaInformation lai in lais)
                    {
                        if (!String.IsNullOrEmpty(lai.getStreetLayerName()) && lai.getStreetLayerName().Equals(streetTypeCombo.SelectedItem.ToString()))
                        {
                            if (areaTypeRadio.Checked)
                                lai.calculateLandPrice(areaPrices);
                            else
                                lai.calculateLandPrice(landPrices);
                        }
                        if (lai.getLandStreets().Count > 0)
                            count++;
                        String[] items = new String[8] { Convert.ToString(i++), type, lai.getLandCodeDescription(), 
                            lai.getStreetType(), lai.getStreetName(), 
                            lai.getLandAreaSquare().ToString("N", CultureInfo.CurrentCulture), 
                            lai.getLandPriceMin().ToString("N", CultureInfo.CurrentCulture), 
                            lai.getLandPriceMax().ToString("N", CultureInfo.CurrentCulture)};
                        landAreaListView.Items.Add(new ListViewItem(items));
                    }
                }
                this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
            }
            if (count > 0)
            {
                MessageBox.Show(GDCalMessages.Notify_NumberOfLandAreaCalculated + count, GDCalMessages.Notify_Caption);
                this.saveButton.Enabled = true;
            }
            else 
            {
                this.saveButton.Enabled = false;
            }
            loadAreaDataBGWorker.Dispose();
        }

        private void checkAndSaveCalculatedData()
        {
            if (this.saveButton.Enabled && landAreaInformations != null && landAreaInformations.Count > 0)
            {
                DialogResult result = MessageBox.Show(GDCalMessages.Confirm_WantToSaveData, GDCalMessages.Confirm_Caption, MessageBoxButtons.YesNo);
                if(result.Equals(DialogResult.Yes))
                    saveButton_Click(null, null);
            }
        }

        private void loadPriceForCityAtYear(String cityName, Int16 year) 
        {
            landPrices = new Dictionary<String, double>();
            if (!String.IsNullOrEmpty(cityName))
            {
                LandPriceVO filterObj = new LandPriceVO();
                filterObj.setCity(cityName);
                filterObj.setYear(year);
                ArrayList landPriceVOs = LandPriceDao.filter(filterObj);
                ArrayList streetTypeVOs = StreetTypeDao.filter(new StreetTypeVO());
                Dictionary<String, String> streetTypeMappings = getStreetTypeMapping();

                foreach (String streetCode in streetTypeMappings.Keys)
                {
                    int stId = 0;
                    foreach (StreetTypeVO streetType in streetTypeVOs)
                    {
                        if (streetType.getType().Equals(streetTypeMappings[streetCode]))
                        {
                            stId = streetType.getId();
                            break;
                        }
                    }
                    double price = 0;
                    if (stId > 0)
                    {
                        foreach (LandPriceVO landPrice in landPriceVOs)
                        {
                            if (landPrice.getStreetTypeId() == stId)
                            {
                                price = Convert.ToDouble(landPrice.getPrice());
                                break;
                            }
                        }
                    }
                    landPrices.Add(streetTypeMappings[streetCode], price);
                }
            }

            areaPrices = new Dictionary<String, double>();
            if (!String.IsNullOrEmpty(cityName))
            {
                AreaPriceVO filterObj = new AreaPriceVO();
                filterObj.setCity(cityName);
                filterObj.setYear(year);
                ArrayList areaPriceVOs = AreaPriceDao.filter(filterObj);
                ArrayList areaTypeVOs = AreaTypeDao.filter(new AreaTypeVO());
                Dictionary<String, String> areaTypeMappings = getStreetTypeMapping();

                foreach (String areaCode in areaTypeMappings.Keys)
                {
                    int stId = 0;
                    foreach (AreaTypeVO areaType in areaTypeVOs)
                    {
                        if (areaType.getType().Equals(areaTypeMappings[areaCode]))
                        {
                            stId = areaType.getId();
                            break;
                        }
                    }
                    double price = 0;
                    if (stId > 0)
                    {
                        foreach (AreaPriceVO areaPrice in areaPriceVOs)
                        {
                            if (areaPrice.getAreaTypeId() == stId)
                            {
                                price = Convert.ToDouble(areaPrice.getPrice());
                                break;
                            }
                        }
                    }
                    areaPrices.Add(areaTypeMappings[areaCode], price);
                }
            }
        }

        private void landAreaListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            TextFormatFlags flags = TextFormatFlags.Left;
            Rectangle rec = new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width - 4, e.Bounds.Height - 4);

            if (e.ColumnIndex >= 4)
            {
                flags = TextFormatFlags.Right;
            }

            TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.Item.ListView.Font, rec, e.SubItem.ForeColor, flags);
        }

        private void landAreaListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
            e.DrawBackground();
            e.DrawText();
        }

        private void landAreaListView_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            if (Convert.ToDouble(e.Item.SubItems[6].Text) < Convert.ToDouble(e.Item.SubItems[7].Text))
            {
                e.Item.BackColor = Color.RoyalBlue;
                e.DrawBackground();
            }
        }

        private void yearUpDown_ValueChanged(object sender, EventArgs e)
        {
            cityCombo.Items.Clear();
            foreach (String city in this.getCities(Convert.ToInt32(yearUpDown.Value)))
                cityCombo.Items.Add(city);
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            this.setWaitingMode(GDCalMessages.Status_DataSaving, this.mainStatus, this.mainStatusLabel);
            TreeNode node = this.mainTree.SelectedNode;
            String mapKey = node.Parent.Name + "_" + node.Text;
            CityLandPriceVO clpFilterObj = new CityLandPriceVO();
            clpFilterObj.setCity(cityCombo.SelectedItem.ToString());
            clpFilterObj.setYear(Convert.ToInt32(yearUpDown.Value));
            clpFilterObj.setLandLayer(landAreaCombo.SelectedItem.ToString());
            clpFilterObj.setLandAreaAttribute(landAreaAttributeCombo.SelectedItem.ToString());
            clpFilterObj.setMapKey(mapKey);
            ArrayList ret = CityLandPriceDao.filter(clpFilterObj);
            if (ret.Count == 0)
            {
                CityLandPriceDao.insertCityLandPrice(clpFilterObj);
                clpFilterObj = (CityLandPriceVO)CityLandPriceDao.filter(clpFilterObj)[0];
            }
            else
            {
                clpFilterObj = (CityLandPriceVO)ret[0];
            }

            if (landAreaInformations != null && landAreaInformations.Count > 0)
            {
                LandStreetPriceDetailDao.delAllLandStreetByClpId(clpFilterObj.getId());
                foreach (String type in landAreaInformations.Keys)
                {
                    ArrayList lais = landAreaInformations[type];
                    foreach (LandAreaInformation lai in lais)
                    {
                        if (lai.getLandStreets().Count > 0)
                        {
                            LandStreetPriceDetailVO lspdVO = new LandStreetPriceDetailVO();
                            lspdVO.setClpId(clpFilterObj.getId());
                            lspdVO.setLandIdentify(type);
                            lspdVO.setLandArea(Convert.ToDecimal(lai.getLandAreaSquare()));
                            lspdVO.setStreetIdentify(lai.getStreetType());
                            lspdVO.setStreetName(lai.getStreetName());
                            lspdVO.setMaxPrice(Convert.ToDecimal(lai.getLandPriceMax()));
                            lspdVO.setMinPrice(Convert.ToDecimal(lai.getLandPriceMin()));
                            lspdVO.setStreetLayerName(lai.getStreetLayerName());
                            lspdVO.setLandAreaByBuffer(lai.getAreaByBufferStr());
                            lspdVO.setLandCodeDescription(lai.getLandCodeDescription());
                            LandStreetPriceDetailDao.insertLandStreetPriceDetail(lspdVO);
                        }
                    }
                }
                
            }
            this.clearWaitingMode(this.mainStatus, this.mainStatusLabel);
            MessageBox.Show(GDCalMessages.Notify_Saved, GDCalMessages.Notify_Caption);
            this.saveButton.Enabled = false;
        }

        private void landAreaInfoListView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ListViewItem selectedItem = landAreaInfoListView.GetItemAt(e.X, e.Y);
            LandStreetPriceListDetailForm detailForm = new LandStreetPriceListDetailForm(selectedItem.StateImageIndex);
            detailForm.ShowDialog();
        }

        private void cancelProcess_Click(object sender, EventArgs e)
        {
            cancelProcessButton.Visible = false;
            calButton.Visible = true;
            loadAreaDataBGWorker.Abort();
            loadAreaDataBGWorker.Dispose();
        }

        private void GDCal_FormClosing(object sender, FormClosingEventArgs e)
        {
            checkAndSaveCalculatedData();
        }

        private void streetTypeRadio_CheckedChanged(object sender, EventArgs e)
        {
            if(this.streetTypeCombo.Items.Count > 0)
                this.streetTypeCombo.SelectedIndex = 0;
            else
            {
                this.streetTypeCombo.SelectedIndex = -1;
                this.streetTypeCombo.SelectedText = "";
            }
            this.streetTypeCombo.Enabled = true;
            this.streetNameAttribute.Visible = true;
            this.streetNameAttributeCombo.Visible = true;
            this.streetTypeLayerLabel.Text = "Lớp đường xá:";
            this.streetTypeMappingLabel.Text = "Chỉ định kiểu đường tương ứng trong hệ thống:";
            this.layerStreetTypeCol.Text = "Loại đường dùng trong lớp bản đồ";
            this.systemStreetTypeCol.Text = "Loại đường trong hệ thống";
            this.streetTypeAttributes.Text = "Thuộc tính kiểu đường:";
        }

        private void areaTypeRadio_CheckedChanged(object sender, EventArgs e)
        {
            this.streetTypeCombo.SelectedIndex = this.landAreaCombo.SelectedIndex;
            this.streetTypeCombo.Enabled = false;
            this.streetNameAttribute.Visible = false;
            this.streetNameAttributeCombo.Visible = false;
            this.streetNameAttributeCombo.SelectedIndex = -1;
            this.streetNameAttributeCombo.SelectedText = "";
            this.streetTypeLayerLabel.Text = "Lớp thửa đất:";
            this.streetTypeMappingLabel.Text = "Chỉ định kiểu thửa tương ứng trong hệ thống:";
            this.layerStreetTypeCol.Text = "Loại thửa dùng trong lớp bản đồ";
            this.systemStreetTypeCol.Text = "Loại thửa trong hệ thống";
            this.streetTypeAttributes.Text = "Thuộc tính kiểu thửa:";
        }

        private void areaTToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AreaTypeForm areaTypeForm = new AreaTypeForm();
            areaTypeForm.ShowDialog();
        }

        private void areaMToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LandPriceManagementForm landPriceManagementForm = new LandPriceManagementForm(true);
            landPriceManagementForm.ShowDialog();
        }

        private void streetTToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StreetTypeForm streetTypeForm = new StreetTypeForm();
            streetTypeForm.ShowDialog();
        }

        private void streetMToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LandPriceManagementForm landPriceManagementForm = new LandPriceManagementForm(false);
            landPriceManagementForm.ShowDialog();
        }
    }
}
